/**
*
*/
package cn.org.zeronote.orm.generation;
import java.io.File;
import java.io.FileWriter;
import java.io.IOException;
import java.math.BigDecimal;
import java.sql.Connection;
import java.sql.DatabaseMetaData;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import javax.sql.DataSource;
import javax.sql.XADataSource;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 连接数据库,生成代码
* @author <a href='mailto:lizheng8318@gmail.com'>lizheng</a>
*
*/
public class GenerationCodeJDBC implements IGenerationCode {
private static Logger logger = LoggerFactory.getLogger(GenerationCodeJDBC.class);
/**数据源*/
private Connection connection;
/**
*
*/
public GenerationCodeJDBC() {
}
/*
* (non-Javadoc)
* @see cn.org.zeronote.orm.generation.GenerationCode#generate(java.lang.String, java.lang.String)
*/
@Override
public void generate(String pack, String outputFolder, boolean useDefault) {
try {
List<Table> tables = gainTables();
buildSource(pack, outputFolder, tables, useDefault);
} catch (Exception e) {
logger.error("build source error!", e);
}
}
/*
* (non-Javadoc)
* @see cn.org.zeronote.orm.generation.IGenerationCode#generate(java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public void generatePrefix(String prefix, String pack, String outputFolder, boolean useDefault) {
try {
List<Table> tables = gainTables();
List<Table> tabs = new ArrayList<Table>();
for (Table table : tables) {
if (table.getTableName().startsWith(prefix)) {
tabs.add(table);
logger.info("Generat table:{}", table.getTableName());
}
}
if (!tabs.isEmpty()) {
buildSource(pack, outputFolder, tabs, useDefault);
} else {
logger.warn("No table have be Generate!");
}
} catch (Exception e) {
logger.error("build source error!", e);
}
}
/*
* (non-Javadoc)
* @see cn.org.zeronote.orm.generation.IGenerationCode#generateTable(java.lang.String, java.lang.String, java.lang.String)
*/
@Override
public void generateTable(String tableName, String pack, String outputFolder, boolean useDefault) {
try {
List<Table> tables = gainTables();
List<Table> tabs = new ArrayList<Table>();
for (Table table : tables) {
if (table.getTableName().equals(tableName)) {
tabs.add(table);
logger.info("Generat table:{}", tableName);
break;
}
}
if (!tabs.isEmpty()) {
buildSource(pack, outputFolder, tabs, useDefault);
} else {
logger.warn("No table have be Generate!");
}
} catch (Exception e) {
logger.error("build source error!", e);
}
}
/**
* 生成代码
* @param pack pack
* @param outputFolder folder
* @param tables tables
* @throws IOException exception
*/
private void buildSource(String pack, String outputFolder, List<Table> tables, boolean useDefault) throws IOException {
String sepa = File.separator;
if (sepa.equalsIgnoreCase("\\")) {
sepa = "\\\\";
}
String baseDir = outputFolder.endsWith(sepa) ? outputFolder : outputFolder + sepa;
baseDir += pack.replaceAll("\\.", sepa);
File dir = new File(baseDir);
if (!dir.exists()) {
// 创建目录结构
dir.mkdirs();
}
for (Table table : tables) {
String fileName = toBeanName(table.getTableName(), true) + "PO.java";
StringBuilder writeStr = new StringBuilder();
writeStr.append("/**\n * \n */\n")
.append("package ").append(pack).append(";\n\n")
.append("import java.io.Serializable;\n")
.append("\n")
.append("import cn.org.zeronote.orm.ORMAutoAssemble;\n")
.append("import cn.org.zeronote.orm.ORMColumn;\n")
.append("import cn.org.zeronote.orm.ORMTable;\n")
.append("\n\n")
.append("/**\n * Auto Generat Code by system\n")
.append(" * ").append(table.getRemarks()).append("\n")
.append(" *\n */\n")
.append("@ORMAutoAssemble\n");
// tableName
writeStr.append("@ORMTable(tableName = \"").append(table.getTableName()).append("\")\n");
writeStr.append("public class ").append(toBeanName(table.getTableName(), true)).append("PO").append(" implements Serializable{\n")
.append("\n")
.append("\tprivate static final long serialVersionUID = 1L;\n\n");
// columns
StringBuilder sgStr = new StringBuilder(); // get/set方法
for (Column column : table.getColumns()) {
if (column.getRemarks() != null && !"".equalsIgnoreCase(column.getRemarks().trim())) {
writeStr.append("\t")
.append("/** ").append(column.getRemarks()).append(" */\n");
}
writeStr.append("\t")
.append("@ORMColumn(value = \"").append(column.getName()).append("\"");
if (column.isPrimaryKey()) {
writeStr.append(", physicalPkFld = true");
}
if (column.isAutoIncrement()) {
writeStr.append(", autoIncrement = true");
}
if (useDefault) {
// 是否生成默认值
if (!column.isPrimaryKey()
&& column.getDef() != null
) { // 主键/没有默认值
// 默认值,当值在单引号内时应被解释为一个字符串(可为 null)
String val = "\"" + column.getDef() + "\"";
if (column.getClz().equals(Date.class)) {
val = "ORMColumn.DEFAULT_DATE";
}
writeStr.append(", defaultValue=").append(val);
}
}
writeStr.append(")\n");
writeStr.append("\t")
.append("private ").append(column.getClz().getName()).append(" ").append(toBeanName(column.getName(), false)).append(";\n")
.append("\n");
// get
sgStr.append("\t/**\n\t * @return the ").append(toBeanName(column.getName(), false)).append("\n\t */\n")
.append("\t")
.append("public ").append(column.getClz().getName()).append(" get").append(toBeanName(column.getName(), true)).append("() {\n")
.append("\t\t")
.append("return ").append(toBeanName(column.getName(), false)).append(";\n")
.append("\t}\n");
// set
sgStr.append("\t/**\n\t * @param id the ").append(toBeanName(column.getName(), false)).append(" to set\n\t */\n")
.append("\t")
.append("public void set").append(toBeanName(column.getName(), true)).append("(").append(column.getClz().getName()).append(" ").append(toBeanName(column.getName(), false)).append(") {\n")
.append("\t\t")
.append("this.").append(toBeanName(column.getName(), false)).append(" = ").append(toBeanName(column.getName(), false)).append(";\n")
.append("\t}\n");
}
// 构造方法
writeStr.append("\t").append("/**\n\t * \n\t */\n")
.append("\t")
.append("public ").append(toBeanName(table.getTableName(), true)).append("PO").append("() {\n\t}\n");
// get/set方法
writeStr.append(sgStr);
// 结束
writeStr.append("\n}\n");
File f = new File(baseDir + sepa + fileName);
if (f.exists()) {
f.delete();
}
FileWriter out = new FileWriter(f);
out.write(writeStr.toString());
out.flush();
out.close();
}
}
/**
* 转换名称
* @param dbObjName db object name
* @return Bean name
*/
private String toBeanName(String dbObjName, boolean firstUpper) {
// 小写
String name = dbObjName.toLowerCase();
// 分割"_"
String[] strs = name.split("_");
name = ((firstUpper ? strs[0].substring(0,1).toUpperCase() : strs[0].substring(0,1).toLowerCase()) + strs[0].substring(1));
if (strs.length > 1) {
for (int i = 1; i < strs.length; i++) {
// 首字母大写
name += (strs[i].substring(0,1).toUpperCase() + strs[i].substring(1));
}
}
return name;
}
/**
* 获取所有table
* @return table list
* @throws SQLException exception
*/
private List<Table> gainTables() throws SQLException {
List<Table> tables = new ArrayList<Table>();
try {
ResultSet rs = null;
// 所有表
rs = connection.getMetaData().getTables(null, null, null, null);
while (rs.next()) {
Table t = new Table();
t.setTableName(rs.getString("TABLE_NAME"));
t.setRemarks(rs.getString("REMARKS"));
logger.info("tableName:{}", t.getTableName());
tables.add(t);
}
rs.close();
// 所有表中的列
for (Table table : tables) {
// 主键
ResultSet rsp = connection.getMetaData().getPrimaryKeys(null, null, table.getTableName());
List<String> pks = new ArrayList<String>();
while (rsp.next()) {
pks.add(rsp.getString("COLUMN_NAME"));
}
rsp.close();
rsp = null;
// 列
rs = connection.getMetaData().getColumns(null, null, table.getTableName(), null);
while (rs.next()) {
Column c = new Column();
c.setName(rs.getString("COLUMN_NAME"));
if (pks.contains(c.getName())) {
c.setPrimaryKey(true);
}
int dataType = rs.getInt("DATA_TYPE");
c.setClz(toBeanType(dataType));
int nullable = rs.getInt("NULLABLE");
if (DatabaseMetaData.columnNullable == nullable) {
// 明确指出可以为空
c.setNullable(true);
} else {
c.setNullable(false);
}
c.setDef(rs.getString("COLUMN_DEF")); // 默认值
c.setAutoIncrement("YES".equals(rs.getString("IS_AUTOINCREMENT")));
c.setRemarks(rs.getString("REMARKS")); // 注释
logger.info("tableName:{}; column:{}", table.getTableName(), c.getName());
table.getColumns().add(c);
}
rs.close();
}
} catch (SQLException e) {
throw e;
} finally {
try {
connection.close();
} catch (SQLException e) {
}
}
return tables;
}
/**
* 转换bean需要的类型定义
* @param type db object type
* @return pojo class
*/
private Class<?> toBeanType(int type) {
Class<?> clz = typesMap.get(type);
return clz == null ? String.class : clz;
}
/**
* set datasource
* @param dataSource the dataSource to set
* @throws SQLException exception
*/
public void setDataSource(DataSource dataSource) throws SQLException {
this.connection = dataSource.getConnection();
}
/**
* set xa datasource
* @param dataSource the XAdataSource to set
* @throws SQLException exception
*/
public void setXADataSource(XADataSource dataSource) throws SQLException {
this.connection = dataSource.getXAConnection().getConnection();
}
/**
* set datasource connection
* @param connection conn
*/
public void setConnection(Connection connection) {
this.connection = connection;
}
/** 数据库类型映射,保存非String类型的对应关系,其它类型默认String */
private static Map<Integer, Class<?>> typesMap = new HashMap<Integer, Class<?>>();
static {
typesMap.put(java.sql.Types.BIGINT, Long.class);
typesMap.put(java.sql.Types.BOOLEAN, Boolean.class);
typesMap.put(java.sql.Types.DATE, Date.class);
typesMap.put(java.sql.Types.DECIMAL, BigDecimal.class);
typesMap.put(java.sql.Types.DOUBLE, Double.class);
typesMap.put(java.sql.Types.FLOAT, Float.class);
typesMap.put(java.sql.Types.INTEGER, Integer.class);
typesMap.put(java.sql.Types.SMALLINT, Integer.class);
typesMap.put(java.sql.Types.TINYINT, Integer.class);
typesMap.put(java.sql.Types.NUMERIC, Number.class);
typesMap.put(java.sql.Types.TIME, Date.class);
typesMap.put(java.sql.Types.TIMESTAMP, Date.class);
}
}